home *** CD-ROM | disk | FTP | other *** search
/ The World of Computer Software / The World of Computer Software.iso / faq-s.zip / ASYNC12.PAS < prev    next >
Pascal/Delphi Source File  |  1990-10-11  |  60KB  |  1,255 lines

  1. {****************************************************************************}
  2. {*                                                                          *}
  3. {*  ASYNC12 - Interrupt-driven asyncronous communications for Turbo Pascal  *}
  4. {*                 Version 1.2 - Wedensday June 14, 1989                    *}
  5. {*             Copyright (C) 1989, Rising Edge Data Services                *}
  6. {*                         Author : Mark Schultz                            *}
  7. {*                                                                          *}
  8. {*--------------------------------------------------------------------------*}
  9. {*                                                                          *}
  10. {*  The routines that follow comprise a Turbo Pascal UNIT that will fully   *}
  11. {*  impliment interrupt-driven serial communications on a fully PC-compat-  *}
  12. {*  able computer (those machines that use the 8250 or equivalent UART      *}
  13. {*  mapped at the standard addresses).  Full simultaneous buffering for     *}
  14. {*  both input and output with variable buffer sizes for each port is       *}
  15. {*  provided.  Unlike many other libraries of a similar nature, up to 4     *}
  16. {*  ports may be active simultaneously (easily modified for more).          *}
  17. {*                                                                          *}
  18. {*  For further details, consult the procedure/function headers within the  *}
  19. {*  program or check the accompanying ASYNC12.DOC file.  To successfuly     *}
  20. {*  compile this unit, you MUST have the file "ASYNC.OBJ" in the "Object    *}
  21. {*  directory" (as defined in the Integrated Environment) or the currently  *}
  22. {*  logged directory; in short, where the compiler can find it.  This file  *}
  23. {*  contains the object code for the assembly-based routines within.        *}
  24. {*                                                                          *}
  25. {*  This product is copyrighted (C) 1988 by Rising Edge Software, Inc. and  *}
  26. {*  it's author, Mark Schultz.  Permission is granted for non-commercial    *}
  27. {*  use and distribution.  Refer to the file ASYNC12.DOC for details.       *}
  28. {*                                                                          *}
  29. {*  Version History:                                                        *}
  30. {*                                                                          *}
  31. {*  V1.2 - Improved performance (accuracy) of the ComExist function.        *}
  32. {*         Several minor enhancements made to improve performance.          *}
  33. {*                                                                          *}
  34. {*  V1.1 - Corrected errors that dealt with the handling of the 8259.  Also *}
  35. {*         added compensation for "bugs" that are present in some 8250's    *}
  36. {*         and equivalent gate arrays (Thanks to Ralph Schraven, Toshiba    *}
  37. {*         Europa GmbH for tracking these problems down).                   *}
  38. {*                                                                          *}
  39. {*  V1.0 - First release                                                    *}
  40. {*                                                                          *}
  41. {*--------------------------------------------------------------------------*}
  42. {*                                                                          *}
  43. {*  Status byte definition (C_Status):                                      *}
  44. {*                                                                          *}
  45. {*  7   6   5   4   3   2   1   0                                           *}
  46. {*  |   |   |   |   |   |   |   |____ Input buffer empty                    *}
  47. {*  |   |   |   |   |   |   |________ Input buffer full                     *}
  48. {*  |   |   |   |   |   |____________ Output buffer empty                   *}
  49. {*  |   |   |   |   |________________ Output buffer full                    *}
  50. {*  |   |   |   |____________________ Input buffer overflow                 *}
  51. {*  |   |   |________________________ Output buffer overflow                *}
  52. {*  |   |____________________________ Hard handshake active (xmit stopped)  *}
  53. {*  |________________________________ Soft handshake active (xmit stopped)  *}
  54. {*                                                                          *}
  55. {*  Control byte definition (C_Ctrl):                                       *}
  56. {*                                                                          *}
  57. {*  7   6   5   4   3   2   1   0                                           *}
  58. {*  |   |   |   |   |   |   |   |____ Enable RTS handshake                  *}
  59. {*  |   |   |   |   |   |   |________ Enable CTS handshake                  *}
  60. {*  |   |   |   |   |   |____________ Enable software handshake             *}
  61. {*  |   |   |   |   |________________                                       *}
  62. {*  |   |   |   |____________________                                       *}
  63. {*  |   |   |________________________                                       *}
  64. {*  |   |____________________________                                       *}
  65. {*  |________________________________                                       *}
  66. {*                                                                          *}
  67. {****************************************************************************}
  68.  
  69. {$R-,V-,B-}
  70.  
  71. Unit ASYNC12;
  72.  
  73. INTERFACE
  74.  
  75. {----------------------------------------------------------------------------}
  76.  
  77. Const
  78.   C_MinBaud = 50;
  79.   C_MaxBaud = 115200;
  80.  
  81.   { Base port addresses & interrupt usage }
  82.  
  83.   C_MaxPort = 4;
  84.   C_MaxCom : Byte = C_MaxPort;
  85.   C_PortAddr : Array[1..C_MaxPort] Of Word = ($03F8,$02F8,$03E8,$02E8);
  86.   C_PortInt : Array[1..C_MaxPort] Of Byte = (4,3,4,3);
  87.  
  88. {----------------------------------------------------------------------------}
  89.  
  90. Type
  91.   C_PointerArray = Array[1..C_MaxPort] Of Pointer;
  92.   C_WordArray = Array[1..C_MaxPort] Of Word;
  93.   C_ByteArray = Array[1..C_MaxPort] Of Byte;
  94.   C_CharArray = Array[1..C_MaxPort] Of Char;
  95.   C_BooleanArray = Array[1..C_MaxPort] Of Boolean;
  96.  
  97. {----------------------------------------------------------------------------}
  98.  
  99. Var
  100.   C_InBufPtr,C_OutBufPtr : C_PointerArray;    { Input/output buffer pointers }
  101.   C_InHead,C_OutHead     : C_WordArray;       { Input/output head pointers }
  102.   C_InTail,C_OutTail     : C_WordArray;       { Input/output tail pointers }
  103.   C_InSize,C_OutSize     : C_WordArray;       { Input/output buffer sizes }
  104.   C_RTSOn,C_RTSOff       : C_WordArray;       { RTS assert/drop buffer points }
  105.   C_StartChar,C_StopChar : C_CharArray;       { Soft hndshake start/stop char }
  106.   C_Status,C_Ctrl        : C_ByteArray;       { STATUS and CONTROL registers }
  107.   C_XL3Ptr               : C_ByteArray;
  108.   C_PortOpen             : C_BooleanArray;    { Port open/close flags }
  109.   C_Temp : Word;                              { Used for debugging }
  110.  
  111. {----------------------------------------------------------------------------}
  112.  
  113. { Procedure headers - required for UNITization }
  114.  
  115. Function  ComReadCh(ComPort:Byte) : Char;
  116. Function  ComReadChW(ComPort:Byte) : Char;
  117. Procedure ComWriteCh(ComPort:Byte; Ch:Char);
  118. Procedure ComWriteChW(ComPort:Byte; Ch:Char);
  119. Procedure SetDTR(ComPort:Byte; Assert:Boolean);
  120. Procedure SetRTS(ComPort:Byte; Assert:Boolean);
  121. Procedure SetOUT1(ComPort:Byte; Assert:Boolean);
  122. Procedure SetOUT2(ComPort:Byte; Assert:Boolean);
  123. Function  CTSStat(ComPort:Byte) : Boolean;
  124. Function  DSRStat(ComPort:Byte) : Boolean;
  125. Function  RIStat(ComPort:Byte) : Boolean;
  126. Function  DCDStat(ComPort:Byte) : Boolean;
  127. Procedure SetRTSMode(ComPort:Byte; Mode:Boolean; RTSOn,RTSOff:Word);
  128. Procedure SetCTSMode(ComPort:Byte; Mode:Boolean);
  129. Procedure SoftHandshake(ComPort:Byte; Mode:Boolean; Start,Stop:Char);
  130. Procedure ClearCom(ComPort:Byte; IO:Char);
  131. Function  ComBufferLeft(ComPort:Byte; IO:Char) : Word;
  132. Procedure ComWaitForClear(ComPort:Byte);
  133. Procedure ComWrite(ComPort:Byte; St:String);
  134. Procedure ComWriteln(ComPort:Byte; St:String);
  135. Procedure ComWriteWithDelay(ComPort:Byte; St:String; Dly:Word);
  136. Procedure ComReadln(ComPort:Byte; Var St:String; Size:Byte; Echo:Boolean);
  137. Function  ComExist(ComPort:Byte) : Boolean;
  138. Function  ComTrueBaud(Baud:Longint) : Real;
  139. Procedure ComParams(ComPort:Byte; Baud:LongInt; WordSize:Byte; Parity:Char; StopBits:Byte);
  140. Function  OpenCom(ComPort:Byte; InBufferSize,OutBufferSize:Word) : Boolean;
  141. Procedure CloseCom(ComPort:Byte);
  142. Procedure CloseAllComs;
  143.  
  144. {----------------------------------------------------------------------------}
  145.  
  146. IMPLEMENTATION
  147.  
  148. Uses DOS,CRT;
  149.  
  150. {$L ASYNC.OBJ}
  151.  
  152. Const
  153.   C_IER = 1;                           { 8250 register offsets }
  154.   C_IIR = 2;
  155.   C_LCR = 3;
  156.   C_MCR = 4;
  157.   C_LSR = 5;
  158.   C_MSR = 6;
  159.   C_SCR = 7;
  160.  
  161. Var
  162.   C_OldINTVec : C_PointerArray;        { Storage for old hardware INT vectors }
  163.   X : Byte;                            { Used by initialization code }
  164.  
  165. {****************************************************************************}
  166. {*                                                                          *}
  167. {*  Procedure INT_Handler; External;                                        *}
  168. {*                                                                          *}
  169. {*  Hardware interrupts 3 and 4 (vectors $0B and $0C) are pointed to        *}
  170. {*  this routine.  It is for internal use only and should NOT be called     *}
  171. {*  directly.  Written in assembly language (see ASYNC12.ASM).              *}
  172. {*                                                                          *}
  173. {****************************************************************************}
  174.  
  175. Procedure INT_Handler; External;
  176.  
  177. {****************************************************************************}
  178. {*                                                                          *}
  179. {*  Procedure ComReadCh(ComPort:Byte) : Char; External;                     *}
  180. {*                                                                          *}
  181. {*  ComPort:Byte  ->  Port # to use (1 - C_MaxCom)                          *}
  182. {*                                                                          *}
  183. {*  Returns character from input buffer of specified port.  If the buffer   *}
  184. {*  is empty, the port # invalid or not opened, a Chr(0) is returned.       *}
  185. {*  Written in assembly language for best possible speed (see ASYNC12.ASM)  *}
  186. {*                                                                          *}
  187. {****************************************************************************}
  188.  
  189. Function ComReadCh(ComPort:Byte) : Char; External;
  190.  
  191. {****************************************************************************}
  192. {*                                                                          *}
  193. {*  Function ComReadChW(ComPort:Byte) : Char; External;                     *}
  194. {*                                                                          *}
  195. {*  ComPort:Byte  ->  Port # to use (1 - C_MaxCom)                          *}
  196. {*                                                                          *}
  197. {*  Works like ComReadCh, but will wait until at least 1 character is       *}
  198. {*  present in the specified input buffer before exiting.  Thus, ComReadChW *}
  199. {*  works much like the ReadKey predefined function.  Written in assembly   *}
  200. {*  language to maximize performance (see ASYNC12.ASM)                      *}
  201. {*                                                                          *}
  202. {****************************************************************************}
  203.  
  204. Function ComReadChW(ComPort:Byte) : Char; External;
  205.  
  206. {****************************************************************************}
  207. {*                                                                          *}
  208. {*  Procedure ComWriteCh(ComPort:Byte; Ch:Char); External                   *}
  209. {*                                                                          *}
  210. {*  ComPort:Byte  ->  Port # to use (1 - C_MaxCom)                          *}
  211. {*  Ch:Char       ->  Character to send                                     *}
  212. {*                                                                          *}
  213. {*  Places the character [Ch] in the transmit buffer of the specified port. *}
  214. {*  If the port specified is not open or nonexistent, or if the buffer is   *}
  215. {*  filled, the character is discarded.  Written in assembly language to    *}
  216. {*  maximize performance (see ASYNC12.ASM)                                  *}
  217. {*                                                                          *}
  218. {****************************************************************************}
  219.  
  220. Procedure ComWriteCh(ComPort:Byte; Ch:Char); External;
  221.  
  222. {****************************************************************************}
  223. {*                                                                          *}
  224. {*  Procedure ComWriteChW(ComPort:Byte; Ch:Char); External;                 *}
  225. {*                                                                          *}
  226. {*  ComPort:Byte  ->  Port # to use (1 - C_MaxCom)                          *}
  227. {*  Ch:Char       ->  Character to send                                     *}
  228. {*                                                                          *}
  229. {*  Works as ComWriteCh, but will wait until at least 1 free position is    *}
  230. {*  available in the output buffer before attempting to place the character *}
  231. {*  [Ch] in it.  Allows the programmer to send characters without regard to *}
  232. {*  available buffer space.  Written in assembly language to maximize       *}
  233. {*  performance (see ASYNC12.ASM)                                           *}
  234. {*                                                                          *}
  235. {****************************************************************************}
  236.  
  237. Procedure ComWriteChW(ComPort:Byte; Ch:Char); External;
  238.  
  239. {****************************************************************************}
  240. {*                                                                          *}
  241. {*  Procedure SetDTR(ComPort:Byte; Assert:Boolean);                         *}
  242. {*                                                                          *}
  243. {*  ComPort:Byte    ->  Port # to use (1 - C_MaxCom)                        *}
  244. {*                      Call ignored if out-of-range                        *}
  245. {*  Assert:Boolean  ->  DTR assertion flag (TRUE to assert DTR)             *}
  246. {*                                                                          *}
  247. {*  Provides a means to control the port's DTR (Data Terminal Ready) signal *}
  248. {*  line.  When [Assert] is TRUE, the DTR line is placed in the "active"    *}
  249. {*  state, signalling to a remote system that the host is "on-line"         *}
  250. {*  (although not nessesarily ready to receive data - see SetRTS).          *}
  251. {*                                                                          *}
  252. {****************************************************************************}
  253.  
  254. Procedure SetDTR(ComPort:Byte; Assert:Boolean);
  255.  
  256. Var
  257.   P,X : Integer;
  258.  
  259. Begin
  260.   If (ComPort<1) Or (ComPort>C_MaxCom) Then Exit;
  261.   P := C_PortAddr[ComPort];
  262.  
  263.   X := Port[P+C_MCR];
  264.   If Assert Then
  265.     X := X Or $01
  266.   Else
  267.     X := X And $FE;
  268.   Port[P+C_MCR] := X;
  269. End;
  270.  
  271. {****************************************************************************}
  272. {*                                                                          *}
  273. {*  Procedure SetRTS(ComPort:Byte; Assert:Boolean)                          *}
  274. {*                                                                          *}
  275. {*  ComPort:Byte    ->  Port # to use (1 - C_MaxCom)                        *}
  276. {*                      Call ignored if out-of-range                        *}
  277. {*  Assert:Boolean  ->  RTS assertion flag (Set TRUE to assert RTS)         *}
  278. {*                                                                          *}
  279. {*  SetRTS allows a program to manually control the Request-To-Send (RTS)   *}
  280. {*  signal line.  If RTS handshaking is disabled (see C_Ctrl definition     *}
  281. {*  and the the SetRTSMode procedure), this procedure may be used.  SetRTS  *}
  282. {*  should NOT be used if RTS handshaking is enabled.                       *}
  283. {*                                                                          *}
  284. {****************************************************************************}
  285.  
  286. Procedure SetRTS(ComPort:Byte; Assert:Boolean);
  287.  
  288. Var
  289.   P,X : Integer;
  290.  
  291. Begin
  292.   If (ComPort<1) Or (ComPort>C_MaxCom) Then Exit;
  293.   P := C_PortAddr[ComPort];
  294.  
  295.   X := Port[P+C_MCR];
  296.   If Assert Then
  297.     X := X Or $02
  298.   Else
  299.     X := X And $FD;
  300.   Port[P+C_MCR] := X;
  301. End;
  302.  
  303. {****************************************************************************}
  304. {*                                                                          *}
  305. {*  Procedure SetOUT1(ComPort:Byte; Assert:Boolean)                         *}
  306. {*                                                                          *}
  307. {*  ComPort:Byte    ->  Port # to use (1 - C_MaxCom)                        *}
  308. {*                      Call ignored if out-of-range                        *}
  309. {*  Assert:Boolean  ->  OUT1 assertion flag (set TRUE to assert OUT1 line)  *}
  310. {*                                                                          *}
  311. {*  SetOUT1 is provided for reasons of completeness only, since the         *}
  312. {*  standard PC/XT/AT configurations do not utilize this control signal.    *}
  313. {*  If [Assert] is TRUE, the OUT1 signal line on the 8250 will be set to a  *}
  314. {*  LOW logic level (inverted logic).  The OUT1 signal is present on pin 34 *}
  315. {*  of the 8250 (but not on the port itself).                               *}
  316. {*                                                                          *}
  317. {****************************************************************************}
  318.  
  319. Procedure SetOUT1(ComPort:Byte; Assert:Boolean);
  320.  
  321. Var
  322.   P,X : Integer;
  323.  
  324. Begin
  325.   If (ComPort<1) Or (ComPort>C_MaxCom) Then Exit;
  326.   P := C_PortAddr[ComPort];
  327.  
  328.   X := Port[P+C_MCR];
  329.   If Assert Then
  330.     X := X Or $04
  331.   Else
  332.     X := X And $FB;
  333.   Port[P+C_MCR] := X;
  334. End;
  335.  
  336. {****************************************************************************}
  337. {*                                                                          *}
  338. {*  Procedure SetOUT2(ComPort:Byte; Assert:Boolean)                         *}
  339. {*                                                                          *}
  340. {*  ComPort:Byte    ->  Port # to use (1 - C_MaxCom)                        *}
  341. {*                      Call ignored if out-of-range                        *}
  342. {*  Assert:Boolean  ->  OUT2 assertion flag (set TRUE to assert OUT2 line)  *}
  343. {*                                                                          *}
  344. {*  The OUT2 signal line, although not available on the port itself, is     *}
  345. {*  used to gate the 8250 <INTRPT> (interrupt) line and thus acts as a      *}
  346. {*  redundant means of controlling 8250 interrupts.  When [Assert] is TRUE, *}
  347. {*  the /OUT2 line on the 8250 is lowered, which allows the passage of the  *}
  348. {*  <INTRPT> signal through a gating arrangement, allowing the 8250 to      *}
  349. {*  generate interrupts.  Int's can be disabled bu unASSERTing this line.   *}
  350. {*                                                                          *}
  351. {****************************************************************************}
  352.  
  353. Procedure SetOUT2(ComPort:Byte; Assert:Boolean);
  354.  
  355. Var
  356.   P,X : Integer;
  357.  
  358. Begin
  359.   If (ComPort<1) Or (ComPort>C_MaxCom) Then Exit;
  360.   P := C_PortAddr[ComPort];
  361.  
  362.   X := Port[P+C_MCR];
  363.   If Assert Then
  364.     X := X Or $08
  365.   Else
  366.     X := X And $F7;
  367.   Port[P+C_MCR] := X;
  368. End;
  369.  
  370. {****************************************************************************}
  371. {*                                                                          *}
  372. {*  Function CTSStat(ComPort:Byte) : Boolean                                *}
  373. {*                                                                          *}
  374. {*  ComPort:Byte  ->  Port # to use (1 - C_MaxCom)                          *}
  375. {*                    Call ignored if out-of-range                          *}
  376. {*  Returns status of Clear-To-Send line (TRUE if CTS asserted)             *}
  377. {*                                                                          *}
  378. {*  CTSStat provides a means to interrogate the Clear-To-Send hardware      *}
  379. {*  handshaking line.  In a typical arrangement, when CTS is asserted, this *}
  380. {*  signals the host (this computer) that the receiver is ready to accept   *}
  381. {*  data (in contrast to the DSR line, which signals the receiver as        *}
  382. {*  on-line but not nessesarily ready to accept data).  An automated mech-  *}
  383. {*  ansim (see CTSMode) is provided to do this, but in cases where this is  *}
  384. {*  undesirable or inappropriate, the CTSStat function can be used to int-  *}
  385. {*  terrogate this line manually.                                           *}
  386. {*                                                                          *}
  387. {****************************************************************************}
  388.  
  389. Function CTSStat(ComPort:Byte) : Boolean;
  390.  
  391. Begin
  392.   If (ComPort<1) Or (ComPort>C_MaxCom) Then
  393.     CTSStat := False
  394.   Else
  395.     CTSStat := (Port[C_PortAddr[ComPort]+C_MSR] And $10) > 0;
  396. End;
  397.  
  398. {****************************************************************************}
  399. {*                                                                          *}
  400. {*  Function DSRStat(ComPort:Byte) : Boolean                                *}
  401. {*                                                                          *}
  402. {*  ComPort:Byte  ->  Port # to use (1 - C_MaxCom)                          *}
  403. {*                    Call ignored if out-of-range                          *}
  404. {*  Returns status of Data Set Ready (DSR) signal line.                     *}
  405. {*                                                                          *}
  406. {*  The Data Set Ready (DSR) line is typically used by a remote station     *}
  407. {*  to signal the host system that it is on-line (although not nessesarily  *}
  408. {*  ready to receive data yet - see CTSStat).  A remote station has the DSR *}
  409. {*  line asserted if DSRStat returns TRUE.                                  *}
  410. {*                                                                          *}
  411. {****************************************************************************}
  412.  
  413. Function DSRStat(ComPort:Byte) : Boolean;
  414.  
  415. Begin
  416.   If (ComPort<1) Or (ComPort>C_MaxCom) Then
  417.     DSRStat := False
  418.   Else
  419.     DSRStat := (Port[C_PortAddr[ComPort]+C_MSR] And $20) > 0;
  420. End;
  421.  
  422. {****************************************************************************}
  423. {*                                                                          *}
  424. {*  Function RIStat(ComPort:Byte) : Boolean                                 *}
  425. {*                                                                          *}
  426. {*  ComPort:Byte  ->  Port # to use (1 - C_MaxCom)                          *}
  427. {*                    Call ignored if out-of-range                          *}
  428. {*                                                                          *}
  429. {*  Returns the status of the Ring Indicator (RI) line.  This line is       *}
  430. {*  typically used only by modems, and indicates that the modem has detect- *}
  431. {*  ed an incoming call if RIStat returns TRUE.                             *}
  432. {*                                                                          *}
  433. {****************************************************************************}
  434.  
  435. Function RIStat(ComPort:Byte) : Boolean;
  436.  
  437. Begin
  438.   If (ComPort<1) Or (ComPort>C_MaxCom) Then
  439.     RIStat := False
  440.   Else
  441.     RIStat := (Port[C_PortAddr[ComPort]+C_MSR] And $40) > 0;
  442. End;
  443.  
  444. {****************************************************************************}
  445. {*                                                                          *}
  446. {*  Function DCDStat(ComPort:Byte) : Boolean                                *}
  447. {*                                                                          *}
  448. {*  ComPort:Byte  ->  Port # to use (1 - C_MaxCom)                          *}
  449. {*                    Call ignored if out-of-range                          *}
  450. {*                                                                          *}
  451. {*  Returns the status of the Data Carrier Detect (DCD) line from the rem-  *}
  452. {*  ote device, typically a modem.  When asserted (DCDStat returns TRUE),   *}
  453. {*  the modem indicates that it has successfuly linked with another modem   *}
  454. {*  device at another site.                                                 *}
  455. {*                                                                          *}
  456. {****************************************************************************}
  457.  
  458. Function DCDStat(ComPort:Byte) : Boolean;
  459.  
  460. Begin
  461.   If (ComPort<1) Or (ComPort>C_MaxCom) Then
  462.     DCDStat := False
  463.   Else
  464.     DCDStat := (Port[C_PortAddr[ComPort]+C_MSR] And $80) > 0;
  465. End;
  466.  
  467. {****************************************************************************}
  468. {*                                                                          *}
  469. {*  Procedure SetRTSMode(ComPort:Byte; Mode:Boolean; RTSOn,RTSOff:Word)     *}
  470. {*                                                                          *}
  471. {*  ComPort:Byte  ->  Port # to use (1 - C_MaxCom).                         *}
  472. {*                    Request ignored if out of range or unopened.          *}
  473. {*  Mode:Boolean  ->  TRUE to enable automatic RTS handshake                *}
  474. {*  RTSOn:Word    ->  Buffer-usage point at which the RTS line is asserted  *}
  475. {*  RTSOff:Word   ->  Buffer-usage point at which the RTS line is dropped   *}
  476. {*                                                                          *}
  477. {*  SetRTSMode enables or disables automated RTS handshaking.  If [MODE] is *}
  478. {*  TRUE, automated RTS handshaking is enabled.  If enabled, the RTS line   *}
  479. {*  will be DROPPED when the # of buffer bytes used reaches or exceeds that *}
  480. {*  of [RTSOff].  The RTS line will then be re-asserted when the buffer is  *}
  481. {*  emptied down to the [RTSOn] usage point.  If either [RTSOn] or [RTSOff] *}
  482. {*  exceeds the input buffer size, they will be forced to (buffersize-1).   *}
  483. {*  If [RTSOn] > [RTSOff] then [RTSOn] will be the same as [RTSOff].        *}
  484. {*  The actual handshaking control is located in the interrupt driver for   *}
  485. {*  the port (see ASYNC12.ASM).                                             *}
  486. {*                                                                          *}
  487. {****************************************************************************}
  488.  
  489. Procedure SetRTSMode(ComPort:Byte; Mode:Boolean; RTSOn,RTSOff:Word);
  490.  
  491. Var
  492.   X : Byte;
  493.  
  494. Begin
  495.   If (ComPort<1) Or (ComPort>C_MaxPort) Or (Not C_PortOpen[ComPort]) Then Exit;
  496.  
  497.   X := C_Ctrl[ComPort];
  498.   If Mode Then X := X Or $01 Else X := X And $FE;
  499.   C_Ctrl[ComPort] := X;
  500.  
  501.   If Mode Then
  502.     Begin
  503.       If (RTSOff >= C_InSize[ComPort]) Then RTSOff := C_InSize[ComPort] - 1;
  504.       If (RTSOn > RTSOff) Then RTSOff := RTSOn;
  505.       C_RTSOn[ComPort] := RTSOn;
  506.       C_RTSOff[ComPort] := RTSOff;
  507.     End;
  508. End;
  509.  
  510. {****************************************************************************}
  511. {*                                                                          *}
  512. {*  Procedure SetCTSMode(ComPort:Byte; Mode:Boolean)                        *}
  513. {*                                                                          *}
  514. {*  ComPort:Byte  ->  Port # to use (1 - C_MaxCom).                         *}
  515. {*                    Request ignored if out of range or unopened.          *}
  516. {*  Mode:Boolean  ->  Set to TRUE to enable automatic CTS handshake.        *}
  517. {*                                                                          *}
  518. {*  SetCTSMode allows the enabling or disabling of automated CTS handshak-  *}
  519. {*  ing.  If [Mode] is TRUE, CTS handshaking is enabled, which means that   *}
  520. {*  if the remote drops the CTS line, the transmitter will be disabled      *}
  521. {*  until the CTS line is asserted again.  Automatic handshake is disabled  *}
  522. {*  if [Mode] is FALSE.  CTS handshaking and "software" handshaking (pro-   *}
  523. {*  vided by the SoftHandshake procedure) ARE compatable and may be used    *}
  524. {*  in any combination.  The actual logic for CTS handshaking is located    *}
  525. {*  in the communications interrupt driver (see ASYNC12.ASM).               *}
  526. {*                                                                          *}
  527. {****************************************************************************}
  528.  
  529. Procedure SetCTSMode(ComPort:Byte; Mode:Boolean);
  530.  
  531. Var
  532.   X : Byte;
  533.  
  534. Begin
  535.   If (ComPort<1) Or (ComPort>C_MaxPort) Or (Not C_PortOpen[ComPort]) Then Exit;
  536.  
  537.   X := C_Ctrl[ComPort];
  538.   If Mode Then X := X Or $02 Else X := X And $FD;
  539.   C_Ctrl[ComPort] := X;
  540. End;
  541.  
  542. {****************************************************************************}
  543. {*                                                                          *}
  544. {*  Procedure SoftHandshake(ComPort:Byte; Mode:Boolean; Start,Stop:Char)    *}
  545. {*                                                                          *}
  546. {*  ComPort:Byte  ->  Port # to use (1 - C_MaxCom).                         *}
  547. {*                    Request ignored if out of range or unopened.          *}
  548. {*  Mode:Boolean  ->  Set to TRUE to enable transmit software handshake     *}
  549. {*  Start:Char    ->  START control character (usually ^Q)                  *}
  550. {*                    Defaults to ^Q if character passed is >= <Space>      *}
  551. {*  Stop:Char     ->  STOP control character (usually ^S)                   *}
  552. {*                    Defaults to ^S if character passed is >= <Space>      *}
  553. {*                                                                          *}
  554. {*  SoftHandshake controls the usage of "Software" (control-character)      *}
  555. {*  handshaking on transmission.  If "software handshake" is enabled        *}
  556. {*  ([Mode] is TRUE), transmission will be halted if the character in       *}
  557. {*  [Stop] is received.  Transmission is re-enabled if the [Start] char-    *}
  558. {*  acter is received.  Both the [Start] and [Stop] characters MUST be      *}
  559. {*  CONTROL characters (i.e. Ord(Start) and Ord(Stop) must both be < 32).   *}
  560. {*  Also, <Start> and <Stop> CANNOT be the same character.  If either one   *}
  561. {*  of these restrictions are violated, the defaults (^Q for <Start> and ^S *}
  562. {*  for <Stop>) will be used.  Software handshaking control is implimented  *}
  563. {*  within the communications interrupt driver (see ASYNC12.ASM).           *}
  564. {*                                                                          *}
  565. {****************************************************************************}
  566.  
  567. Procedure SoftHandshake(ComPort:Byte; Mode:Boolean; Start,Stop:Char);
  568.  
  569. Var
  570.   X : Byte;
  571.  
  572. Begin
  573.   If (ComPort<1) Or (ComPort>C_MaxPort) Or (Not C_PortOpen[ComPort]) Then Exit;
  574.  
  575.   X := C_Ctrl[ComPort];
  576.   If Mode Then
  577.     Begin
  578.       X := X Or $04;
  579.       If Start=Stop Then Begin Start := ^Q; Stop := ^S; End;
  580.       If Start>#32 Then Start := ^Q;
  581.       If Stop>#32 Then Stop := ^S;
  582.       C_StartChar[ComPort] := Start;
  583.       C_StopChar[ComPort] := Stop;
  584.     End
  585.   Else
  586.     X := X And $FB;
  587.   C_Ctrl[ComPort] := X;
  588. End;
  589.  
  590. {****************************************************************************}
  591. {*                                                                          *}
  592. {*  Procedure ClearCom(ComPort:Byte); IO:Char)                              *}
  593. {*                                                                          *}
  594. {*  ComPort:Byte  ->  Port # to use (1 - C_MaxCom).                         *}
  595. {*                    Request ignored if out of range or unopened.          *}
  596. {*  IO:Char       ->  Action code; I=Input, O=Output, B=Both                *}
  597. {*                    No action taken if action code unrecognized.          *}
  598. {*                                                                          *}
  599. {*  ClearCom allows the user to completely clear the contents of either     *}
  600. {*  the input (receive) and/or output (transmit) buffers.  The "action      *}
  601. {*  code" passed in <IO> determines if the input (I) or output (O) buffer   *}
  602. {*  is cleared.  Action code (B) will clear both buffers.  This is useful   *}
  603. {*  if you wish to cancel a transmitted message or ignore part of a         *}
  604. {*  received message.                                                       *}
  605. {*                                                                          *}
  606. {****************************************************************************}
  607.  
  608. Procedure ClearCom(ComPort:Byte; IO:Char);
  609.  
  610. Var
  611.   P,X : Word;
  612.  
  613. Begin
  614.   If (ComPort<1) Or (ComPort>C_MaxCom) Or (Not C_PortOpen[ComPort]) Then Exit;
  615.  
  616.   IO := Upcase(IO);
  617.   P := C_PortAddr[ComPort];
  618.  
  619.   Inline($FA);
  620.   If (IO='I') Or (IO='B') Then
  621.     Begin
  622.       C_InHead[ComPort] := 0;
  623.       C_InTail[ComPort] := 0;
  624.       C_Status[ComPort] := (C_Status[ComPort] And $EC) Or $01;
  625.       X := Port[P] + Port[P+C_LSR] + Port[P+C_MSR] + Port[P+C_IIR];
  626.     End;
  627.   If (IO='O') Or (IO='B') Then
  628.     Begin
  629.       C_OutHead[ComPort] := 0;
  630.       C_OutTail[ComPort] := 0;
  631.       C_Status[ComPort] := (C_Status[ComPort] And $D3) Or $04;
  632.       X := Port[P+C_LSR] + Port[P+C_MSR] + Port[P+C_IIR];
  633.     End;
  634.   Inline($FB);
  635. End;
  636.  
  637. {****************************************************************************}
  638. {*                                                                          *}
  639. {*  Procedure ComBufferLeft(ComPort:Byte; IO:Char) : Word                   *}
  640. {*                                                                          *}
  641. {*  ComPort:Byte  ->  Port # to use (1 - C_MaxCom).                         *}
  642. {*                    Returns 0 if Port # invalid or unopened.              *}
  643. {*  IO:Char       ->  Action code; I=Input, O=Output                        *}
  644. {*                    Returns 0 if action code unrecognized.                *}
  645. {*                                                                          *}
  646. {*  ComBufferLeft will return a number (bytes) indicating how much space    *}
  647. {*  remains in the selected buffer.  The INPUT buffer is checked if <IO> is *}
  648. {*  (I), and the output buffer is interrogated when <IO> is (O).  Any other *}
  649. {*  "action code" will return a result of 0.  Use this function when it is  *}
  650. {*  important to avoid program delays due to calls to output procedures or  *}
  651. {*  to prioritize the reception of data (to prevent overflows).             *}
  652. {*                                                                          *}
  653. {****************************************************************************}
  654.  
  655. Function ComBufferLeft(ComPort:Byte; IO:Char) : Word;
  656.  
  657. Begin
  658.   ComBufferLeft := 0;
  659.   If (ComPort<1) Or (ComPort>C_MaxCom) Or (Not C_PortOpen[ComPort]) Then Exit;
  660.   IO := Upcase(IO);
  661.  
  662.   If IO = 'I' Then
  663.     If C_InHead[ComPort] >= C_InTail[ComPort] Then
  664.       ComBufferLeft := C_InSize[ComPort]-(C_InHead[ComPort]-C_InTail[ComPort])
  665.     Else
  666.       ComBufferLeft := C_InTail[ComPort]-C_InHead[ComPort];
  667.  
  668.   If IO = 'O' Then
  669.     If C_OutHead[ComPort] >= C_OutTail[ComPort] Then
  670.       ComBufferLeft := C_OutHead[ComPort]-C_OutTail[ComPort]
  671.     Else
  672.       ComBufferLeft := C_OutSize[ComPort]-(C_OutTail[ComPort]-C_OutHead[ComPort]);
  673. End;
  674.  
  675. {****************************************************************************}
  676. {*                                                                          *}
  677. {*  Procedure ComWaitForClear(ComPort:Byte)                                 *}
  678. {*                                                                          *}
  679. {*  ComPort:Byte  ->  Port # to use (1 - C_MaxCom).                         *}
  680. {*                    Exits immediately if out of range or port unopened.   *}
  681. {*                                                                          *}
  682. {*  A call to ComWaitForClear will stop processing until the selected out-  *}
  683. {*  put buffer is completely emptied.  Typically used just before a call    *}
  684. {*  to the CloseCom procedure to prevent premature cut-off of messages in   *}
  685. {*  transit.                                                                *}
  686. {*                                                                          *}
  687. {****************************************************************************}
  688.  
  689. Procedure ComWaitForClear(ComPort:Byte);
  690.  
  691. Var
  692.   Empty : Boolean;
  693.  
  694. Begin
  695.   If (ComPort<1) Or (ComPort>C_MaxCom) Or (Not C_PortOpen[ComPort]) Then Exit;
  696.   Repeat
  697.     Empty := (C_Status[ComPort] And $04) = $04;
  698.     Empty := Empty And ((Port[C_PortAddr[ComPort]+C_IER] And $02) = $00);
  699.   Until Empty;
  700. End;
  701.  
  702. {****************************************************************************}
  703. {*                                                                          *}
  704. {*  Procedure ComWrite(ComPort:Byte; St:String)                             *}
  705. {*                                                                          *}
  706. {*  ComPort:Byte  ->  Port # to use (1 - C_MaxCom).                         *}
  707. {*                    Exits immediately if out of range or port unopened.   *}
  708. {*  St:String     ->  String to send                                        *}
  709. {*                                                                          *}
  710. {*  Sends string <St> out communications port <ComPort>.                    *}
  711. {*                                                                          *}
  712. {****************************************************************************}
  713.  
  714. Procedure ComWrite(ComPort:Byte; St:String);
  715.  
  716. Var
  717.   X : Byte;
  718.  
  719. Begin
  720.   If (ComPort<1) Or (ComPort>C_MaxCom) Or (Not C_PortOpen[ComPort]) Then Exit;
  721.  
  722.   For X := 1 To Length(St) Do
  723.     ComWriteChW(ComPort,St[X]);
  724. End;
  725.  
  726. {****************************************************************************}
  727. {*                                                                          *}
  728. {*  Procedure ComWriteln(ComPort:Byte; St:String);                          *}
  729. {*                                                                          *}
  730. {*  ComPort:Byte  ->  Port # to use (1 - C_MaxCom).                         *}
  731. {*                    Exits immediately if out of range or port unopened.   *}
  732. {*  St:String     ->  String to send                                        *}
  733. {*                                                                          *}
  734. {*  Sends string <St> with a CR and LF appended.                            *}
  735. {*                                                                          *}
  736. {****************************************************************************}
  737.  
  738. Procedure ComWriteln(ComPort:Byte; St:String);
  739.  
  740. Var
  741.   X : Byte;
  742.  
  743. Begin
  744.   If (ComPort<1) Or (ComPort>C_MaxCom) Or (Not C_PortOpen[ComPort]) Then Exit;
  745.  
  746.   For X := 1 To Length(St) Do
  747.     ComWriteChW(ComPort,St[X]);
  748.   ComWriteChW(ComPort,#13);
  749.   ComWriteChW(ComPort,#10);
  750. End;
  751.  
  752. {****************************************************************************}
  753. {*                                                                          *}
  754. {*  Procedure ComWriteWithDelay(ComPort:Byte; St:String; Dly:Word);         *}
  755. {*                                                                          *}
  756. {*  ComPort:Byte  ->  Port # to use (1 - C_MaxCom).                         *}
  757. {*                    Exits immediately if out of range or port unopened.   *}
  758. {*  St:String     ->  String to send                                        *}
  759. {*  Dly:Word      ->  Time, in milliseconds, to delay between each char.    *}
  760. {*                                                                          *}
  761. {*  ComWriteWithDelay will send string <St> to port <ComPort>, delaying     *}
  762. {*  for <Dly> milliseconds between each character.  Useful for systems that *}
  763. {*  cannot keep up with transmissions sent at full speed.                   *}
  764. {*                                                                          *}
  765. {****************************************************************************}
  766.  
  767. Procedure ComWriteWithDelay(ComPort:Byte; St:String; Dly:Word);
  768.  
  769. Var
  770.   X : Byte;
  771.  
  772. Begin
  773.   If (ComPort<1) Or (ComPort>C_MaxCom) Or (Not C_PortOpen[ComPort]) Then Exit;
  774.  
  775.   ComWaitForClear(ComPort);
  776.   For X := 1 To Length(St) Do
  777.     Begin
  778.       ComWriteChW(ComPort,St[X]);
  779.       ComWaitForClear(ComPort);
  780.       Delay(Dly);
  781.     End;
  782. End;
  783.  
  784. {****************************************************************************}
  785. {*                                                                          *}
  786. {* Procedure ComReadln(ComPort:Byte; Var St:String; Size:Byte; Echo:Boolean)*}
  787. {*                                                                          *}
  788. {*  ComPort:Byte  ->  Port # to use (1 - C_MaxCom).                         *}
  789. {*                    Exits immediately if out of range or port unopened.   *}
  790. {*  St:String     <-  Edited string from remote                             *}
  791. {*  Size:Byte;    ->  Maximum allowable length of input                     *}
  792. {*  Echo:Boolean; ->  Set TRUE to echo received characters                  *}
  793. {*                                                                          *}
  794. {*  ComReadln is the remote equivalent of the standard Pascal READLN pro-   *}
  795. {*  cedure with some enhancements.  ComReadln will accept an entry of up to *}
  796. {*  40 printable ASCII characters, supporting ^H and ^X editing commands.   *}
  797. {*  Echo-back of the entry (for full-duplex operation) is optional.  All    *}
  798. {*  control characters, as well as non-ASCII (8th bit set) characters are   *}
  799. {*  stripped.  If <Echo> is enabled, ASCII BEL (^G) characters are sent     *}
  800. {*  when erroneous characters are intercepted.  Upon receipt of a ^M (CR),  *}
  801. {*  the procedure is terminated and the final string result returned.       *}
  802. {*                                                                          *}
  803. {****************************************************************************}
  804.  
  805. Procedure ComReadln(ComPort:Byte; Var St:String; Size:Byte; Echo:Boolean);
  806.  
  807. Var
  808.   Len,X : Byte;
  809.   Ch : Char;
  810.   Done : Boolean;
  811.  
  812. Begin
  813.   St := '';
  814.   If (ComPort<1) Or (ComPort>C_MaxCom) Or (Not C_PortOpen[ComPort]) Then Exit;
  815.  
  816.   Done := False;
  817.   Repeat
  818.     Len := Length(St);
  819.     Ch := Chr(Ord(ComReadChW(ComPort)) And $7F);
  820.  
  821.     Case Ch Of
  822.       ^H : If Len > 0 Then
  823.              Begin
  824.                Dec(Len);
  825.                St[0] := Chr(Len);
  826.                If Echo Then ComWrite(ComPort,#8#32#8);
  827.              End
  828.            Else
  829.              ComWriteChW(ComPort,^G);
  830.       ^M : Begin
  831.              Done := True;
  832.              If Echo Then ComWrite(ComPort,#13#10);
  833.            End;
  834.       ^X : Begin
  835.              St := '';
  836.              If Len = 0 Then ComWriteCh(ComPort,^G);
  837.              If Echo Then
  838.                For X := 1 to Len Do
  839.                  ComWrite(ComPort,#8#32#8);
  840.            End;
  841.       #32..#127 : If Len < Size Then
  842.                     Begin
  843.                       Inc(Len);
  844.                       St[Len] := Ch;
  845.                       St[0] := Chr(Len);
  846.                       If Echo Then ComWriteChW(ComPort,Ch);
  847.                     End
  848.                   Else
  849.                     If Echo Then ComWriteChW(ComPort,^G);
  850.     Else
  851.       If Echo Then ComWriteChW(ComPort,^G)
  852.     End;
  853.  
  854.   Until Done;
  855. End;
  856.  
  857. {****************************************************************************}
  858. {*                                                                          *}
  859. {*  Function ComExist(ComPort:Byte) : Boolean                               *}
  860. {*                                                                          *}
  861. {*  ComPort:Byte  ->  Port # to use (1 - C_MaxCom)                          *}
  862. {*                    Returns FALSE if out of range                         *}
  863. {*  Returns TRUE if hardware for selected port is detected & tests OK       *}
  864. {*                                                                          *}
  865. {*  Function ComExist performs a high-speed short loopback test on the      *}
  866. {*  selected port to determine if it indeed exists.  Use this function      *}
  867. {*  before attempts to OPEN a port for I/O (although this function is       *}
  868. {*  called by OpenCom to prevent such an occurance).                        *}
  869. {*  NOTE!  Although pains are taken to preserve the 8250 state before the   *}
  870. {*  port test takes place, it is nonetheless recommended that this function *}
  871. {*  NOT be called while a port is actually OPEN.  Doing so may cause the    *}
  872. {*  port to behave erratically.                                             *}
  873. {*                                                                          *}
  874. {****************************************************************************}
  875.  
  876. Function ComExist(ComPort:Byte) : Boolean;
  877.  
  878. Const
  879.   TestByte1 : Byte = $0F;
  880.   TestByte2 : Byte = $F1;
  881.  
  882. Var
  883.   P : Word;
  884.   M,L,B1,B2,X : Byte;
  885.  
  886. Label
  887.   ERROR_EXIT;
  888.  
  889. Begin
  890.   Inline($9C/$FA);
  891.   ComExist := False;
  892.   If (ComPort<1) Or (ComPort>C_MaxPort) Then Exit;
  893.  
  894.   P := C_PortAddr[ComPort];
  895.   M := Port[P+C_MCR];                            { Save MCR }
  896.   L := Port[P+C_LCR];                            { Save LCR }
  897.   Port[P+C_MCR] := $10;                          { Enable loopback mode }
  898.   Port[P+C_LCR] := $80;                          { Enable divisor latch mode }
  899.   B1 := Port[P];                                 { Save current baud rate }
  900.   B2 := Port[P+1];
  901.   Port[P] := 4;                                  { Set baud rate to 28000 }
  902.   Port[P+1] := 0;
  903.   Port[P+C_LCR] := $03;                          { Transmit mode 28000:8N1 }
  904.  
  905.   Delay(20);                                     { Wait a bit }
  906.   X := Port[P] + Port[P];                        { Clear register }
  907.   Port[P] := TestByte1;                          { Test byte #1 }
  908.   Delay(20);                                     { Wait for loopback }
  909.   X := Port[P];                                  { Get byte echoed back }
  910.   If X <> TestByte1 Then Goto ERROR_EXIT;        { Exit w/error if not echoed }
  911.   Port[P] := TestByte2;                          { Test byte #2 }
  912.   Delay(20);                                     { Wait for loopback }
  913.   X := Port[P];                                  { Get echo-back byte }
  914.   If X <> TestByte2 Then Goto ERROR_EXIT;        { Exit w/error if not echoed }
  915.   Port[P] := 0;
  916.  
  917.   ComExist := True;                              { Test passed: Port exists }
  918.  
  919. ERROR_EXIT:
  920.   Port[P+C_LCR] := $80;                          { Restore baud rate }
  921.   Port[P] := B1;
  922.   Port[P+1] := B2;
  923.   Port[P+C_LCR] := L;                            { Restore parameters }
  924.   Port[P+C_MCR] := M;                            { Restore control lines }
  925.   Inline($9D);
  926. End;
  927.  
  928. {****************************************************************************}
  929. {*                                                                          *}
  930. {*  Function ComTrueBaud(Baud:Longint) : Real                               *}
  931. {*                                                                          *}
  932. {*  Baud:Longint  ->  User baud rate to test.                               *}
  933. {*                    Should be between C_MinBaud and C_MaxBaud.            *}
  934. {*  Returns the actual baud rate based on the accuracy of the 8250 divider. *}
  935. {*                                                                          *}
  936. {*  The ASYNC12 communications package allows the programmer to select ANY  *}
  937. {*  baud rate, not just those that are predefined by the BIOS or other      *}
  938. {*  agency.  Since the 8250 uses a divider/counter chain to generate it's   *}
  939. {*  baud clock, many non-standard baud rates can be generated.  However,    *}
  940. {*  the binary counter/divider is not always capable of generating the      *}
  941. {*  EXACT baud rate desired by a user.  This function, when passed a valid  *}
  942. {*  baud rate, will return the ACTUAL baud rate that will be generated.     *}
  943. {*  The baud rate is based on a 8250 input clock rate of 1.73728 MHz.       *}
  944. {*                                                                          *}
  945. {****************************************************************************}
  946.  
  947. Function ComTrueBaud(Baud:Longint) : Real;
  948.  
  949. Var
  950.   X : Real;
  951.   Y : Word;
  952.  
  953. Begin
  954.   X := Baud;
  955.   If X < C_MinBaud Then X := C_MinBaud;
  956.   If X > C_MaxBaud Then X := C_MaxBaud;
  957.   ComTrueBaud := C_MaxBaud / Round($900/(X/50));
  958. End;
  959.  
  960. {****************************************************************************}
  961. {*                                                                          *}
  962. {*  Procedure ComParams(ComPort:Byte; Baud:Longint;                         *}
  963. {*                      WordSize:Byte; Parity:Char; StopBits:Byte);         *}
  964. {*                                                                          *}
  965. {*  ComPort:Byte   ->  Port # to initialize.  Must be (1 - C_MaxCom)        *}
  966. {*                     Procedure aborted if port # invalid or unopened.     *}
  967. {*  Baud:Longint   ->  Desired baud rate.  Should be (C_MinBaud - C_MaxBaud)*}
  968. {*                     C_MinBaud or C_MaxBaud used if out of range.         *}
  969. {*  WordSize:Byte  ->  Word size, in bits.  Must be 5 - 8 bits.             *}
  970. {*                     8-bit word used if out of range.                     *}
  971. {*  Parity:Char    ->  Parity classification.                               *}
  972. {*                     May be N)one, E)ven, O)dd, M)ark or S)pace.          *}
  973. {*                     N)one selected if classification unknown.            *}
  974. {*  StopBits:Byte  ->  # of stop bits to pad character with.  Range (1-2)   *}
  975. {*                     1 stop bit used if out of range.                     *}
  976. {*                                                                          *}
  977. {*  ComParams is used to configure an OPEN'ed port for the desired comm-    *}
  978. {*  unications parameters, namely baud rate, word size, parity form and     *}
  979. {*  # of stop bits.  A call to this procedure will set up the port approp-  *}
  980. {*  riately, as well as assert the DTR, RTS and OUT2 control lines and      *}
  981. {*  clear all buffers.                                                      *}
  982. {*                                                                          *}
  983. {****************************************************************************}
  984.  
  985. Procedure ComParams(ComPort:Byte; Baud:LongInt; WordSize:Byte; Parity:Char; StopBits:Byte);
  986.  
  987. Const
  988.   C_Stopbit1    = $00;                 { Bit masks for parity, stopbits }
  989.   C_Stopbit2    = $04;
  990.   C_NoParity    = $00;
  991.   C_OddParity   = $08;
  992.   C_EvenParity  = $18;
  993.   C_MarkParity  = $28;
  994.   C_SpaceParity = $38;
  995.  
  996. Var
  997.   X : Real;
  998.   Y,P : Word;
  999.   DivMSB,DivLSB : Byte;
  1000.   WS,SB,PTY : Byte;
  1001.  
  1002. Begin
  1003.   If (ComPort<1) Or (ComPort>C_MaxPort) Or (Not C_PortOpen[ComPort]) Then Exit;
  1004.  
  1005.   Inline($9C/$FA);
  1006.   P := C_PortAddr[ComPort];
  1007.  
  1008.   { Calculate baud rate divisors }
  1009.  
  1010.   X := Baud;
  1011.   If X < C_MinBaud Then X := C_MinBaud;
  1012.   If X > C_MaxBaud Then X := C_MaxBaud;
  1013.   Y := Round($900/(X/50));
  1014.   DivMSB := Hi(Y);
  1015.   DivLSB := Lo(Y);
  1016.  
  1017.   { Determine parity mask }
  1018.   { Default if unknown: No parity }
  1019.  
  1020.   Case UpCase(Parity) Of
  1021.     'N' : PTY := C_NoParity;
  1022.     'E' : PTY := C_EvenParity;
  1023.     'O' : PTY := C_OddParity;
  1024.     'M' : PTY := C_MarkParity;
  1025.     'S' : PTY := C_SpaceParity;
  1026.   Else
  1027.     PTY := C_NoParity;
  1028.   End;
  1029.  
  1030.   { Determine stop-bit mask }
  1031.   { Default if out of range: 1 Stop bit }
  1032.  
  1033.   Case StopBits Of
  1034.     1 : SB := C_StopBit1;
  1035.     2 : SB := C_StopBit2;
  1036.   Else
  1037.     SB := C_StopBit1;
  1038.   End;
  1039.  
  1040.   { Determine word-size mask }
  1041.   { Default if out of range: 8 bit word size }
  1042.  
  1043.   If (WordSize >= 5) And (WordSize <= 8) Then
  1044.     WS := WordSize - 5
  1045.   Else
  1046.     WS := 3;
  1047.  
  1048.   { Initialize line-control register }
  1049.  
  1050.   Port[P+C_LCR] := WS + SB + PTY;
  1051.  
  1052.   { Initialize baud rate divisor latches }
  1053.  
  1054.   Port[P+C_LCR] := Port[P+C_LCR] Or $80;
  1055.   Port[P] := DivLSB;
  1056.   Port[P+1] := DivMSB;
  1057.   Port[P+C_LCR] := Port[P+C_LCR] And $7F;
  1058.   X := Port[P] + Port[P+C_LSR] + Port[P+C_MSR] + Port[P+C_IIR];
  1059.  
  1060.   { Assert RS323 control lines (DTR,RTS,OUT2) & exit }
  1061.  
  1062.   Port[P+C_MCR] := $0B;
  1063.   ClearCom(ComPort,'B');
  1064.   Inline($9D);
  1065. End;
  1066.  
  1067. {****************************************************************************}
  1068. {*                                                                          *}
  1069. {*  Function OpenCom(ComPort:Byte; InBufferSize,OutBufferSize:Word):Boolean *}
  1070. {*                                                                          *}
  1071. {*  ComPort:Byte        ->  Port # to OPEN (1 - C_MaxCom)                   *}
  1072. {*                          Request will fail if out of range or port OPEN  *}
  1073. {*  InBufferSize:Word   ->  Requested size of input (receive) buffer        *}
  1074. {*  OutBufferSize:Word  ->  Requested size of output (transmit) buffer      *}
  1075. {*  Returns success/fail status of OPEN request (TRUE if OPEN successful)   *}
  1076. {*                                                                          *}
  1077. {*  OpenCom must be called before any activity (other than existence check, *}
  1078. {*  see the ComExist function) takes place.  OpenCom initializes the        *}
  1079. {*  interrupt drivers and serial communications hardware for the selected   *}
  1080. {*  port, preparing it for I/O.  Memory for buffers is allocated on the     *}
  1081. {*  Pascal "heap", thus freeing data-segment memory for larger more data-   *}
  1082. {*  intensive programs.  Once a port has been OPENed, a call to ComParams   *}
  1083. {*  should be made to set up communications parameters (baud rate, parity   *}
  1084. {*  and the like).  Once this is done, I/O can take place on the port.      *}
  1085. {*  OpenCom will return a TRUE value if the opening procedure was success-  *}
  1086. {*  ful, or FALSE if it is not.                                             *}
  1087. {*                                                                          *}
  1088. {****************************************************************************}
  1089.  
  1090. Function OpenCom(ComPort:Byte; InBufferSize,OutBufferSize:Word) : Boolean;
  1091.  
  1092. Var
  1093.   TempVec : Pointer;
  1094.   P : Word;
  1095.   IntLn,X : Byte;
  1096.  
  1097. Begin
  1098.   { Ensure that port was not previously open }
  1099.  
  1100.   OpenCom := False;
  1101.   If (ComPort<1) Or (ComPort>C_MaxPort) Or C_PortOpen[ComPort] Then Exit;
  1102.   If Not ComExist(ComPort) Then Exit;
  1103.  
  1104.   { Clear any pending activity from 8250 interrupt queue }
  1105.  
  1106.   Inline($9C/$FA);
  1107.   P := C_PortAddr[ComPort];
  1108.   Port[P+C_IER] := $0D;
  1109.   X := Port[P] + Port[P+C_LSR] + Port[P+C_MSR] + Port[P+C_IIR];
  1110.  
  1111.   { Set up interrupt vectors & 8259 PIC }
  1112.  
  1113.   IntLn := C_PortInt[ComPort];
  1114.   GetIntVec(8+IntLn,TempVec);
  1115.   If C_OldINTVec[IntLn] <> TempVec Then
  1116.     Begin
  1117.       C_OldINTVec[IntLn] := TempVec;
  1118.       SetIntVec(8+IntLn,@Int_Handler);
  1119.       Port[$21] := Port[$21] And (($01 SHL IntLn) XOR $FF);
  1120.       X := Port[$21];
  1121.       Port[$20] := $20;
  1122.     End;
  1123.  
  1124.   { Allocate memory for I/O buffers }
  1125.  
  1126.   C_InSize[ComPort] := InBufferSize;
  1127.   C_OutSize[ComPort] := OutBufferSize;
  1128.   GetMem(C_InBufPtr[ComPort],InBufferSize);
  1129.   GetMem(C_OutBufPtr[ComPort],OutBufferSize);
  1130.  
  1131.   { Set up default parameters for port }
  1132.  
  1133.   C_RTSOn[ComPort] := InBufferSize - 2;
  1134.   C_RTSOff[ComPort] := InBufferSize - 1;
  1135.   C_StartChar[ComPort] := ^Q;
  1136.   C_StopChar[ComPort] := ^S;
  1137.   C_Ctrl[ComPort] := 0;
  1138.   C_Status[ComPort] := 5;
  1139.   C_PortOpen[ComPort] := True;
  1140.   OpenCom := True;
  1141.  
  1142.   Inline($9D);
  1143. End;
  1144.  
  1145. {****************************************************************************}
  1146. {*                                                                          *}
  1147. {*  Procedure CloseCom(ComPort:Byte)                                        *}
  1148. {*                                                                          *}
  1149. {*  ComPort:Byte  ->  Port # to close                                       *}
  1150. {*                    Request ignored if port closed or out of range.       *}
  1151. {*                                                                          *}
  1152. {*  CloseCom will un-link the interrupt drivers for a port, deallocate it's *}
  1153. {*  buffers and drop the DTR and RTS signal lines for a port opened with    *}
  1154. {*  the OpenCom function.  It should be called before exiting your program  *}
  1155. {*  to ensure that the port is properly shut down.                          *}
  1156. {*  NOTE:  CloseCom shuts down a communications channel IMMEDIATELY,        *}
  1157. {*         even if there is data present in the input or output buffers.    *}
  1158. {*         Therefore, you may wish to call the ComWaitForClear procedure    *}
  1159. {*         before closing the ports.                                        *}
  1160. {*                                                                          *}
  1161. {****************************************************************************}
  1162.  
  1163. Procedure CloseCom(ComPort:Byte);
  1164.  
  1165. Var
  1166.   ClosePort : Boolean;
  1167.   P,IntLn,X : Word;
  1168.  
  1169. Begin
  1170.   If (ComPort<1) Or (ComPort>C_MaxPort) Or (Not C_PortOpen[ComPort]) Then Exit;
  1171.  
  1172.   { Drop RS232 control lines (DTR,RTS,OUT2) and reset 8250 interrupt mode }
  1173.  
  1174.   Inline($9C/$FA);
  1175.   P := C_PortAddr[ComPort];
  1176.   Port[P+C_MCR] := 0;
  1177.   Port[P+C_IER] := 0;
  1178.   C_PortOpen[ComPort] := False;
  1179.  
  1180.   { Reset INT vectors & 8259 PIC if all COMs on selected INT are closed }
  1181.  
  1182.   IntLn := C_PortInt[ComPort];
  1183.   ClosePort := True;
  1184.   For X := 1 To C_MaxCom Do
  1185.     If C_PortOpen[X] And (C_PortInt[X] = IntLn) Then
  1186.       ClosePort := False;
  1187.  
  1188.   If ClosePort Then
  1189.     Begin
  1190.       X := Port[$21];
  1191.       Port[$21] := X Or ($01 SHR IntLn);
  1192.       X := Port[$21];
  1193.       Port[$20] := $20;
  1194.       SetIntVec(8+IntLn,C_OldINTVec[IntLn]);
  1195.       C_OldINTVec[IntLn] := Nil;
  1196.     End;
  1197.   X := Port[P] + Port[P+C_LSR] + Port[P+C_MSR] + Port[P+C_IIR];
  1198.  
  1199.   { Deallocate buffers }
  1200.  
  1201.   FreeMem(C_InBufPtr[ComPort],C_InSize[ComPort]);
  1202.   FreeMem(C_OutBufPtr[ComPort],C_OutSize[ComPort]);
  1203.   Inline($9D);
  1204. End;
  1205.  
  1206. {****************************************************************************}
  1207. {*                                                                          *}
  1208. {*  Procedure CloseAllComs                                                  *}
  1209. {*                                                                          *}
  1210. {*  CloseAllComs will CLOSE all currently OPENed ports.  See the CloseCom   *}
  1211. {*  procedure description for more details.                                 *}
  1212. {*                                                                          *}
  1213. {****************************************************************************}
  1214.  
  1215. Procedure CloseAllComs;
  1216.  
  1217. Var
  1218.   X : Byte;
  1219.  
  1220. Begin
  1221.   For X := 1 To C_MaxCom Do
  1222.     If C_PortOpen[X] Then
  1223.       CloseCom(X);
  1224. End;
  1225.  
  1226. {****************************************************************************}
  1227. {*                                                                          *}
  1228. {*                        UNIT Initialization Code                          *}
  1229. {*                                                                          *}
  1230. {****************************************************************************}
  1231.  
  1232. Begin
  1233.   For x := 1 to C_MaxPort Do
  1234.     Begin
  1235.       C_PortOpen[x] := False;
  1236.       C_InBufPtr[x] := Nil;
  1237.       C_OutBufPtr[x] := Nil;
  1238.       C_OldIntVec[x] := Nil;
  1239.       C_InHead[x] := 0;
  1240.       C_OutHead[x] := 0;
  1241.       C_InTail[x] := 0;
  1242.       C_OutTail[x] := 0;
  1243.       C_InSize[x] := 0;
  1244.       C_OutSize[x] := 0;
  1245.       C_RTSOn[x] := 0;
  1246.       C_RTSOff[x] := 0;
  1247.       C_StartChar[x] := ^Q;
  1248.       C_StopChar[x] := ^S;
  1249.       C_Status[x] := 5;
  1250.       C_Ctrl[x] := 0;
  1251.       C_XL3Ptr[x] := 0;
  1252.       Port[C_PortAddr[x]+C_MCR] := $00;
  1253.     End;
  1254. End.
  1255.